package com.gitee.l0km.beanfilter.core;

import static com.gitee.l0km.beanfilter.core.CodecPhase.DESERIALIZATION;
import static com.gitee.l0km.beanfilter.core.CodecPhase.SERIALIZATION;
import static com.google.common.base.MoreObjects.firstNonNull;

import com.gitee.l0km.aocache.annotations.AoCacheable;
import com.google.common.base.Supplier;

/**
 * 服务方法拦截器上下文
 * @author guyadong
 *
 */
public class InterceptorContext {

	/** 当前线程的过滤器容器 */
	private static final ThreadLocal<IFilterContainer> CONTAINER_LOCAL = new ThreadLocal<>();
	/**
	 * 返回当前服务拦截上下文中的过滤器容器对象，如果没有返回默认实例
	 */
	public static IFilterContainer getCurrentFilterContainer() {
		return LOCAL_SUPPLIER.get();
	}
	/**
	 * 删除线程局部变量定义的过滤器
	 */
	public static void clearLocal() {
		CONTAINER_LOCAL.remove();
	}

	/**
	 * 安装过滤器
	 * @param container
	 */
	public static void installLocal(IFilterContainer container) {
		CONTAINER_LOCAL.set(container);
	}

	/**
	 * 向序列化/反序列化器注入Bean过滤器
	 * @param filterContainer
	 * @param toSerializingFilterable 
	 * @param toDeserializingFilterable
	 * @param scope 要求的过滤器作用范围
	 */
	public static <E extends Exception> void injectFilter(IFilterContainer filterContainer,
			ThrowingFunction<Class<?>, Filterable, E> toSerializingFilterable, 
			ThrowingFunction<Class<?>,Filterable,E> toDeserializingFilterable, CodecScope scope) throws E{
		installLocal(filterContainer);
		injectFilter(LOCAL_SUPPLIER,
				toSerializingFilterable, SERIALIZATION, scope);
		injectFilter(LOCAL_SUPPLIER,
				toDeserializingFilterable, DESERIALIZATION, scope);
	}

	public static final Supplier<IFilterContainer> LOCAL_SUPPLIER = new Supplier<IFilterContainer> () {

		@Override
		public IFilterContainer get() {
			return firstNonNull(CONTAINER_LOCAL.get(),IFilterContainer.DEFAULT_INSTANCE);
		}};
		
	private static class FilterSupplier<F extends IFilter> implements Supplier<F> {
		final Class<F> filterType;
		final CodecPhase phase;
		final CodecScope scope;
		final Supplier<IFilterContainer> local;
		@AoCacheable
		public FilterSupplier(Supplier<IFilterContainer> local, Class<F> filterType, CodecPhase phase, CodecScope scope) {
			this.local = local;
			this.filterType = filterType;
			this.phase = phase;
			this.scope = scope;
		}
		@SuppressWarnings("unchecked")
		@Override
		public F get() {
			if(IFieldFilter.class.isAssignableFrom(filterType)) {
				return (F) local.get().getScenceFilter(phase, scope).getFieldFilterOrDefault();
				
			}else if(IValueFilter.class.isAssignableFrom(filterType)){
				return (F) local.get().getScenceFilter(phase, scope).getValueFilterOrDefault();
			}
			throw new IllegalArgumentException("INVALID filterType:"+filterType.getName());
		}};
	/**
	 * 向序列化/反序列化器注入Bean过滤器
	 * @param <E>
	 * @param local
	 * @param toFilterable
	 * @param phase
	 * @param scope 要求的过滤器作用范围
	 * @throws E
	 */
	private static <E extends Exception> void injectFilter(Supplier<IFilterContainer> local,
			ThrowingFunction<Class<?>,Filterable,E> toFilterable,CodecPhase phase, CodecScope scope) throws E {
		if(!local.get().getScenceFilter(phase, scope).isEmpty()) {
			for(Class<?> clazz : local.get().associateClasses(phase, scope)) {
				Filterable filterable = toFilterable.apply(clazz);
				if(filterable != null) {
					filterable.injectFilter(
							new FilterSupplier<>(local,IFieldFilter.class,phase, scope), 
							new FilterSupplier<>(local,IValueFilter.class,phase, scope), 
							phase);
				}
			}
		}
	}

}
